package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageBean;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.dto.QueryDeviceDataDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliyunIotProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceServiceImpl implements DeviceService {

    final Client client;
    final StringRedisTemplate stringRedisTemplate;
    final AliyunIotProperties aliyunIotProperties;
    final DeviceMapper deviceMapper;

    /**
     * 同步物联网平台产品列表到Redis
     */
    @Override
    public void syncProductList2Redis() {
        //1. 通过Client对象获取物联网平台产品列表数据
        //创建请求对象
        QueryProductListRequest request = new QueryProductListRequest();
        request.setCurrentPage(1);//页码
        request.setPageSize(100); //每页条数
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());//iot实例id

        //发送请求
        QueryProductListResponse response;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }

        //如果响应状态错误，直接抛异常
        if (!response.body.success) {
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }

        String json = JSON.toJSONString(response.body.data.list.productInfo);
        //2. 将列表数据转json字符串存入redis
        stringRedisTemplate.opsForValue().set(CacheConstants.IOT_ALL_PRODUCT, json);
    }

    /**
     * 查询所有产品列表
     *
     * @return
     */
    @Override
    public List<ProductVo> allProduct() {
        //redis获取数据
        String json = stringRedisTemplate.opsForValue().get(CacheConstants.IOT_ALL_PRODUCT);
        if (StrUtil.isBlank(json)) {
            //返回空集合
            return List.of();
        }

        List<ProductVo> productVoList = JSON.parseArray(json, ProductVo.class);
        return productVoList;
    }

    /**
     * 注册设备
     *
     * @param dto
     */
    @Override
    @Transactional
    public void registerDevice(DeviceDto dto) {
        //1. 将设备的信息注册到阿里云物联网平台(iotid)
        RegisterDeviceResponse response;
        try {
            //设置IotInstanceId
            dto.getRegisterDeviceRequest().setIotInstanceId(aliyunIotProperties.getIotInstanceId());
            response = client.registerDevice(dto.getRegisterDeviceRequest());
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        if (!response.body.success) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        //获取注册成功之后的设备唯一标识
        String iotId = response.body.data.iotId;


        //2. 将设备的信息保存到数据库
        try {
            Device device = BeanUtil.toBean(dto, Device.class);
            device.setIotId(iotId);//设置设备的唯一标识
            //如果是随身设备，将物理位置类型设置为-1
            if (device.getLocationType() == 0) {
                device.setPhysicalLocationType(-1);//0楼层 1房间 2床位 -1老人
            }
            deviceMapper.insert(device);
            //int i = 1 / 0;
        } catch (Exception e) {
            //3. 如果有错误，删除阿里云物联网平台的设备
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotId(iotId); //设备的唯一标识
            deleteDeviceRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());//iot试用实例id
            try {
                client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                ex.printStackTrace();
                log.error("【注册设备】 - 删除阿里云设备失败: {}", ex.toString());
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
    }

    /**
     * 分页查询设备
     *
     * @param dto
     * @return
     */
    @Override
    public PageBean<DeviceVo> pageQuery(DevicePageQueryDto dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        Page<DeviceVo> page = deviceMapper.selectPage(dto);
        return PageBean.of(page, DeviceVo.class);
    }

    /**
     * 查询设备详细数据
     *
     * @param dto
     * @return
     */
    @Override
    public DeviceVo queryDeviceDetail(DeviceDto dto) {
        //1. 查询数据库
        DeviceVo deviceVo = deviceMapper.selectByIotId(dto.getIotId());

        //2. 查询物联网
        QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());//实例id
        request.setIotId(dto.getIotId());//设备唯一标识
        request.setProductKey(dto.getProductKey());//产品key
        QueryDeviceDetailResponse response;
        try {
            response = client.queryDeviceDetail(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }

        if (!response.body.success) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }

        //3. 将物联网查询的设备信息，封装到 deviceVo 中
        BeanUtil.copyProperties(response.body.data, deviceVo);

        //4. 返回
        return deviceVo;
    }


    /**
     * 查询指定设备的物模型运行状态
     *
     * @param request 查询设备的物模型运行状态请求模型
     * @return 物模型运行状态
     */
    @Override
    public DevicePropertyStatusVo queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
        //设置iot实例id
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response;
        try {
            response = client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        //拷贝数据，返回
        DevicePropertyStatusVo devicePropertyStatusVo = BeanUtil.toBean(response.body.data, DevicePropertyStatusVo.class);

        //TODO 对 DevicePropertyStatusVo 对象中的集合排序
        //devicePropertyStatusVo.list.propertyStatusInfo
        CollUtil.sort(devicePropertyStatusVo.list.propertyStatusInfo, (o1, o2) -> StrUtil.equals(o1.getIdentifier(), "HeartRate") ? -1 : 1);

        return devicePropertyStatusVo;
    }

    /**
     * 更新设备
     *
     * @param deviceDto 更新设备请求模型
     */
    @Override
    @Transactional
    public void updateDevice(DeviceDto deviceDto) {
        //更新数据库中设备信息
        try {
            //将dto转换为pojo
            Device device = BeanUtil.toBean(deviceDto, Device.class);
            //判断位置类型：0随身设备，1固定设备        如果是随身设备，将物理位置设为-1
            if (NumberUtil.equals(device.getLocationType(), 0)) {
                device.setPhysicalLocationType(-1);//物理位置类型 0楼层 1房间 2床位 -1随身设备
            }
            deviceMapper.updateByPrimaryKeySelective(device);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

        //调用物联网接口，更新云服务设备信息
        try {
            //创建请求对象
            BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
            //设置iot实例id
            request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());

            //将dto中的数据拷贝到请求对象中
            BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo nicknameInfo =
                    BeanUtil.toBean(deviceDto, BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo.class);
            //设置请求对象信息
            request.setDeviceNicknameInfo(List.of(nicknameInfo));
            //发送请求
            BatchUpdateDeviceNicknameResponse response = client.batchUpdateDeviceNickname(request);
            if (!Boolean.TRUE.equals(response.body.success)) {
                throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
            }
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

    }

    /**
     * 删除设备
     *
     * @param request 删除设备请求模型
     */
    @Override
    @Transactional
    public void deleteDevice(DeleteDeviceRequest request) {
        //1. 删除数据库
        deviceMapper.deleteByIotId(request.getIotId());

        //2. 删除阿里云
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        DeleteDeviceResponse response;
        try {
            response = client.deleteDevice(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }

        if (!response.body.success) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param request 查询已发布物模型请求模型
     * @return 已发布物模型中的功能定义详情
     */
    @Override
    public QueryThingModelVo queryThingModelPublished(QueryThingModelPublishedRequest request) {
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryThingModelPublishedResponse response;
        try {
            response = client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        QueryThingModelVo queryThingModelVo = BeanUtil.toBean(response.getBody().getData(), QueryThingModelVo.class);
        return queryThingModelVo;
    }

}
